package com.ruoyi.common.pay.wxs;

import com.tencent.cloudpay.CloudPay;
import com.tencent.cloudpay.config.Account;
import com.tencent.cloudpay.config.Terminal;
import com.tencent.cloudpay.exception.*;
import com.tencent.cloudpay.param.MicroPayRequest;
import com.tencent.cloudpay.param.MicroPayResponse;
import com.tencent.cloudpay.param.QueryOrderRequest;
import com.tencent.cloudpay.param.QueryOrderResponse;
import com.tencent.cloudpay.pojo.Order;
import com.tencent.cloudpay.pojo.State;
import com.tencent.cloudpay.utils.CommonUtils;

/*
  本例子用来展示如何使用Java SDK的microPay接口

 */
public class MicroPayDemo {
    void init() {
        Account account = new Account("sz013NzuonO6CMJd0rCB",
                "sz01ELTR281OFpmdAp6J",
                "sz019xAikh2E0VfLwLfi",
                "5973",
                "17352");

        String authenKey = "lSCp1M5grGWFD7rJzaZaqixsvOhORp2P"; //

        Terminal terminal = new Terminal(2,
                900,
                "01-01-01-01-01-01",
                "192.168.1.1");


        CloudPay.init(account, authenKey, terminal);
    }

    private boolean isPayResultUnknown(Exception e) {
        return e instanceof CPayNetworkTimeout
                || e instanceof CPayNetworkError
                || e instanceof CPayAuthenCodeCheckFail
                || e instanceof CPayResponseInvalid
                || e instanceof CPayInternalError;
    }

    private boolean isUserPaying(int state) {
        return state == State.kCloudPaySdkLocalStateUserPaying || state == State.kCloudPaySdkLocalStateInit;
    }

    private boolean isPayFailed(int state) {
        return state == State.kCloudPaySdkLocalStateFail || state == State.kCloudPaySdkLocalStateClosed;
    }

    /*
     * @param microPayRequest
     * @return Order 返回的订单信息，如果为null，则说明此时无法确认订单状态，需要用户进行确认
     * @throw exception 说明支付失败
     */
    Order microPay(MicroPayRequest microPayRequest) throws Exception {

        Order order = null;

        // 支付，重试两次
        for (int i = 0; i < 2; i++) {
            try {
                MicroPayResponse microPayResponse = CloudPay.getInstance().microPay(microPayRequest);
                order = microPayResponse.getOrder();

            } catch (Exception e) {
                // 支付结果未知，且是第一次支付的时候，sleep 500ms后重试
                if (isPayResultUnknown(e)) {
                    if (i == 0) {
                        Thread.sleep(500);
                    }
                } else {
                    // 如果是明确错误
                    throw e;
                }
            }
        }

        /*
          向后端轮询查单
           查单的情况有两种：
           1. 网络超时，此时因为网络原因不知道接口是否已调用成功，需要查单确认
           2. 订单状态尚未成功，如用户正在支付中，此时需要轮询确认后端结果
           3. 订单失败
        */
        if (order == null || isUserPaying(order.getState())) {
            //
            long startTime = CommonUtils.getNowTimestamp();
            int sleepTime = 1000;

            while (true) {
                Thread.sleep(sleepTime);

                long nowTime = CommonUtils.getNowTimestamp();

                long diff = nowTime - startTime;

                // 如果已经查了两分钟了，则不再进行轮询
                if (diff >= 120) {
                    order = null;
                    break;
                } else if (diff >= 60) {
                    sleepTime = 5000;
                } else if (diff >= 30) {
                    sleepTime = 2000;
                }

                // 查单
                // 构造请求
                try {
                    QueryOrderRequest queryOrderRequest = new QueryOrderRequest();
                    queryOrderRequest.setOut_trade_no(microPayRequest.getOutTradeNo());

                    QueryOrderResponse queryOrderResponse = CloudPay.getInstance().queryOrder(queryOrderRequest);
                    order = queryOrderResponse.getOrder();

                    int state = order.getState();

                    // 如果订单是成功态了，直接返回成功
                    if (state == State.kCloudPaySdkLocalStateSuccess) {
                        return order;
                    } else if (isPayFailed(state)) {
                        throw new CPayFailed("支付失败");
                    } else {
                        // 用户正在支付中，继续查单
                        continue;
                    }
                } catch (Exception e) {
                    // 如果是网络错误，或者系统内部异常，就重试一次
                    if (isPayResultUnknown(e)) {
                        continue;
                    } else {
                        // 其他异常直接抛出
                        throw e;
                    }
                }
            }
        } else if (isPayFailed(order.getState())) {
            // 支付失败
            throw new CPayFailed("支付失败");
        }

        return order;
    }

    public static void main(String[] args) throws Exception {
        MicroPayDemo demo = new MicroPayDemo();
        demo.init();

        MicroPayRequest microPayRequest = new MicroPayRequest(1,
                "135494350015442969", // 付款码
                1,
                "sz0100lmnx29n189gg",
                "测试",
                CommonUtils.generateNonceStr()
        );

        try {
            Order order = demo.microPay(microPayRequest);

            if (order == null) {
                System.out.println("订单状态未知");
            } else {
                System.out.println(order.getOut_trade_no() + "支付成功");
            }
        } catch (Exception e) {
            System.out.println("支付失败");
            e.printStackTrace();
        }
    }
}
